#include "viewwindow.h"
#include "ui_viewwindow.h"
#include <QMessageBox>
#include "Qt/socketthread.h"
#include "agreement/carinfo.h"
#include "agreement/upload.h"

#ifdef offsetof
#undef offsetof
#endif
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
/**
 * container_of - cast a member of a structure out to the containing structure
 * @ptr:    the pointer to the member.
 * @type:   the type of the container struct this is embedded in.
 * @member: the name of the member within the struct.
 *
 */
#define container_of(ptr, type, member) ({          \
    const typeof(((type *)0)->member)*__mptr = (ptr);    \
             (type *)((char *)__mptr - offsetof(type, member)); })

#include "DateTime.h"
#include <stdio.h>
static void UTC2file(const uint32_t times, void* const buf, const size_t _size)
{
    DateTime      utctime   = {.year = 1970, .month = 1, .day = 1, .hour = 0, .minute = 0, .second = 0};
    DateTime      localtime = {.year = 1970, .month = 1, .day = 1, .hour = 8, .minute = 0, .second = 0};
    if(times > INT32_MAX)
    {
        utctime = GregorianCalendarDateAddSecond(utctime, INT32_MAX);
        utctime = GregorianCalendarDateAddSecond(utctime, (int)(times - INT32_MAX));
    }
    else
    {
        utctime = GregorianCalendarDateAddSecond(utctime, (int)times);
    }

    GregorianCalendarDateToModifiedJulianDate(utctime);
    localtime = GregorianCalendarDateAddHour(utctime, 8);
    snprintf((char *)buf, (size_t)_size, "./log/%d-%.2d-%.2d-%02d%02d%02d.txt", localtime.year, localtime.month, localtime.day, localtime.hour, localtime.minute, localtime.second);
}

ViewWindow::ViewWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::ViewWindow)
{
    char build[128];
    ui->setupUi(this);
    this->setWindowTitle("OBD-Viewer");
    memset(log_path, 0, sizeof (log_path));
    UTC2file(time(NULL), log_path, sizeof (log_path));
    this->setWindowFlags(this->windowFlags()&~Qt::WindowMinMaxButtonsHint);
    ui->lineEdit_IP->setText("39.108.72.130");
#if 1
    ui->lineEdit_PORT->setText("9918");
    //ui->lineEdit_PORT->setText("9910");
#else
    ui->lineEdit_PORT->setText("IP端口不校验，请确保正确！");
#endif
//    ui->lineEdit_IP->setEnabled(false);
//    ui->lineEdit_PORT->setEnabled(false);
#if 0
    ui->comboBox_List_VIN->clear();
    ui->comboBox_List_VIN->addItem("NULL");
    ui->comboBox_List_SN->clear();
    ui->comboBox_List_SN->addItem("NULL");
#else
    on_pushButton_Clear_clicked();
#endif
    ui->pushButton_Connect->setText("Connect");
    ui->lineEdit_time->setEnabled(false);
    ui->lineEdit_Version->setEnabled(false);
    ui->lineEdit_ssl->setEnabled(false);
    ui->checkBox_VIN->setText("VIN过滤");
    ui->checkBox_SN->setText("SN过滤");
    ui->pushButton_Clear->setText("清空显示");
    //ui->groupBox_Pack->setVisible(false);
    //ui->groupBox_Report->setVisible(false);
    //ui->lineEdit_VIN->setVisible(false);
    //ui->lineEdit_SN->setVisible(false);
    memset(build, 0, sizeof (build));
    snprintf(build, sizeof (build)-1, "配置 | Build : %s", __DATE__);
    ui->groupBox_cfg->setTitle(build);
    this->adjustSize();
#if 0
    // OBD
    static struct report_gps gps;
    static OBD_DATA obd;
    static uint8_t msg_buf[4096];
    time_t timer = time(NULL);
    gps.speed = (gps.speed+1)%125;
    gps.longitude = (gps.longitude+1)%180;
    gps.latitude = (gps.latitude+1)%180;
    obd.RTData.Velocity = (obd.RTData.Velocity+5)%700;
    obd.RTData.EngineRev = (obd.RTData.EngineRev+13)%1700;
    obd.RTData.Mileage = (obd.RTData.Mileage+3)%800;
    obd.RTData.FuelConsumption = (obd.RTData.FuelConsumption+7)%900;
    time(&timer);
    shanghai_report_real * _data = shanghai_report_msg(timer, &obd, &gps, msg_buf, sizeof (msg_buf));
    general_pack_shanghai _pack;
    memset(&_pack, 0, sizeof(_pack));
    _pack.data = _data;
    handle_report_real(&_pack);
    //printf("built: %s %s",__TIME__,__DATE__); fflush(stdout);
//    update_vin("LZGJDGN1XHX029925");
//    update_vin("LZGJDGN1XHX029926");
//    update_vin("LZGJDGN1XHX029925");
//    update_vin("LZGJDGN1XHX02995");
#endif
    handle_count=0;
    ui->label_Ready->setText("\n\n\n使用说明：\n");
    ui->label_Ready->setText(ui->label_Ready->text()+"1.IP端口已设置，点击Connect连接服务器;\n");
    ui->label_Ready->setText(ui->label_Ready->text()+"2.VIN与SN过滤为显示已设置的VIN和SN;\n");
    ui->label_Ready->setText(ui->label_Ready->text()+"3.日志自动保存到log目录，请手动创建log目录;\n");
    ui->label_Ready->setText(ui->label_Ready->text()+"4.下拉框记录接收到的VIN和SN号可用于选择过滤;\n");
    ui->label_Ready->setText(ui->label_Ready->text()+"5.清空显示将清空VIN和SN列表，显示区域重置为默认值;\n");
    ui->label_Ready->setText(ui->label_Ready->text()+"\n\n\n");
#if 0
    CreateCarInfo(CarListPath);
    char data[7][128];
    int i=0;
    memset(data, 0, sizeof (data));
    //printf("Car:%d\n", CarInfoSearch(CarListPath, "LGAX3BG42J1026005", &data[0]));
    i = CarInfoSearch(CarListPath, "LGAX3BG42J1026005", data[0]);
    printf("Car:%d\n", i); fflush(stdout);
    for(i=0; i<7; i++)
    {
        qDebug("item_%d : %s", i, data[i]); //fflush(stdout);
    }
    fflush(stdout);
#endif
    pshow = 0;
}

ViewWindow::~ViewWindow()
{
//    int i=0;
    SocketThread::stop();
    MultiThread::stop();
    QThread::usleep(100);
//    pshow = 0;
//    for(i=0; i<1024; i+32)
//    {
//        ViewPrint("                                "); // 32 ' '
//    }
    qDebug("\n~ViewWindow\n"); //fflush(stdout);
    //QThread::usleep(100);
    //delete ui;
    if(nullptr!=ui) delete ui;
    ui = nullptr;
}
#if 1
void ViewWindow::closeEvent(QCloseEvent *event)
{
#if 0
    QMessageBox::StandardButton button;
    button = QMessageBox::question(this, tr("退出程序"),
        QString(tr("警告：程序有一个任务正在运行中，是否结束操作退出?")),
        QMessageBox::Yes | QMessageBox::No);

    if (button == QMessageBox::No) {
        event->ignore();  //忽略退出信号，程序继续运行
    }
    else if (button == QMessageBox::Yes) {
        event->accept();  //接受退出信号，程序退出
    }
#else
    SocketThread::stop();
    MultiThread::stop();
    QThread::sleep(1);
    qDebug("\n~closeEvent\n"); //fflush(stdout);
//    if(nullptr!=ui) delete ui;
//    ui = nullptr;
    event->accept();
//    emit sigClose("ViewWindow");
#endif
}
#endif

void ViewWindow::on_pushButton_Connect_clicked()
{
    QString Connect = ui->pushButton_Connect->text();
//    if(ConnectBusy)
//    {
//        QMessageBox *msgBox;
//            msgBox = new QMessageBox("连接", "警告：上一个连接正在断开，请等待",
//                QMessageBox::Information,
//                QMessageBox::Ok | QMessageBox::Default,
//                QMessageBox::Cancel | QMessageBox::Escape,	0);
//            msgBox->show();
//        return ;
//    }
    if(0==Connect.compare("DisConnect"))
    {
        if(viewer->busy())
        {
            viewer->stop();
            //viewer->CloseSocket();
            //ui->groupBox_Report->setTitle("正在断开连接");
        }
        else
        {
            ui->pushButton_Connect->setText("Connect");
//            viewer->stop();
//            viewer->CloseSocket();
            QThread::usleep(100);
            ui->lineEdit_IP->setEnabled(true);
            ui->lineEdit_PORT->setEnabled(true);
            disconnect(viewer, &MultiThread::resultReady, this, &ViewWindow::handleResults);
            //delete viewer;
            //delete _controller;
            //ui->groupBox_Report->setTitle("连接已断开");
        }
    }
    else
    {
        ui->pushButton_Connect->setText("DisConnect");
        ui->lineEdit_IP->setEnabled(false);
        ui->lineEdit_PORT->setEnabled(false);
        //SocketThread::IP(ui->lineEdit_IP->text(), ui->lineEdit_PORT->text().toInt());
        viewer = new SocketThreadViewer();
        viewer->IP(ui->lineEdit_IP->text(), ui->lineEdit_PORT->text().toInt());
        //connect(viewer, SIGNAL(resultReady(const QString &result, const void* data)), this, SLOT(handleResults(const QString &result, const void* data)));
        connect(viewer, &MultiThread::resultReady, this, &ViewWindow::handleResults);
        _controller = new ControllerMultiThread(viewer);
        _controller->start("Viewer Thread");
    }
}

void ViewWindow::handleResults(const QString result, const void *data)
{
    struct general_pack_shanghai* _pack = (struct general_pack_shanghai *)data;
    QByteArray SN = result.toLatin1();
    QByteArray filter;
    //handle_report_real(_pack);
    //char vin[1024];
    //char* now=NULL;
    //uint16_t index;
    //uint16_t i;

    //memset(vin, 0, sizeof (vin));
    //index = 0;
//    for(i=0; ; i++)
//    {
//        //now = vin_list_for_each(&index);
//    }

    printf("SN:%s\n", SN.data());  fflush(stdout);
    //filter = ui->comboBox_List_VIN->currentText().toLatin1();
    //printf("filter:%s\n", filter.data());  fflush(stdout);
    if((NULL==data) || (0==strcmp("DisConnect", SN.data())) ) // 连接断开
    {
        //if(1!=viewer->busy())
        {
            ui->pushButton_Connect->setText("Connect");
//            viewer->stop();
//            viewer->CloseSocket();
            QThread::usleep(100);
            ui->lineEdit_IP->setEnabled(true);
            ui->lineEdit_PORT->setEnabled(true);
            disconnect(viewer, &MultiThread::resultReady, this, &ViewWindow::handleResults);
            //delete viewer;
            //delete _controller;
            //ui->groupBox_Report->setTitle("连接已断开");
        }
        //ui->groupBox_Report->setTitle(result);
        return;
    }
    handle_count++;
    //ui->groupBox_Report->setTitle("正在接收数据, 帧计数： "+QString::number(handle_count));
    //ui->label_Ready->setText("正在接收数据, 帧计数： "+QString::number(handle_count));
    ui->groupBox_data->setTitle("正在接收数据, 帧计数： "+QString::number(handle_count));
    update_vin((char*)(_pack->VIN));
    update_sn(SN.data());
    pshow = 0;
    if(ui->checkBox_SN->isChecked()) // filter SN
    {
        //filter = ui->lineEdit_SN->text().toLatin1();
        filter = ui->comboBox_List_SN->currentText().toLatin1(); // 获取下拉列表中的当前值
        if(0==strcmp(filter.data(), SN.data()))
        {
            pshow = 1;
        }
    }
    if(ui->checkBox_VIN->isChecked()) // filter VIN
    {
        //filter = ui->lineEdit_VIN->text().toLatin1();
        filter = ui->comboBox_List_VIN->currentText().toLatin1();
        if(0==strcmp(filter.data(), (char *)_pack->VIN))
        {
            pshow = 1;
        }
    }
    //qDebug("isChecked %d", ui->checkBox_SN->isChecked());
    if((!ui->checkBox_SN->isChecked()) && (!ui->checkBox_VIN->isChecked())) pshow = 1;
//    if(pshow) // 显示该数据
//    {
//        ui->label_data->clear();
//    }
    {
        //ui->label_data->clear();
        //ui->groupBox_Pack->setTitle(QString("VIN:%1").arg((char*)_pack->VIN)+QString(" SN:%1").arg(SN.data()));
        ui->groupBox_Pack->setTitle(QString("VIN:%1").arg((char*)_pack->VIN));
        switch(_pack->cmd)
        {
        case CMD_LOGIN:        // 车辆登入
            if(ui->checkBox_Report->isChecked()) pshow = 0;
            if(pshow) ui->label_data->clear();
            ui->label_Ready->setText("车辆登入");
            handle_request_login(_pack);
            break;
        case CMD_REPORT_REAL:  // 实时信息上报
            if(pshow) ui->label_data->clear();
            ui->label_Ready->setText("实时信息上报");
            handle_report_real(_pack);
            break;
        case CMD_REPORT_LATER: // 补发信息上报
            if(pshow) ui->label_data->clear();
            ui->label_Ready->setText("补发信息上报");
            handle_report_real(_pack);
            break;
        case CMD_LOGOUT:       // 车辆登出
            if(ui->checkBox_Report->isChecked()) pshow = 0;
            if(pshow) ui->label_data->clear();
            ui->label_Ready->setText("车辆登出");
            handle_request_logout(_pack);
            break;
        case CMD_UTC:          // 终端校时
            if(ui->checkBox_Report->isChecked()) pshow = 0;
            //if(pshow) ui->label_data->clear();
            ui->label_Ready->setText("终端校时");
            break;
        case CMD_USERDEF:      // 用户自定义
            if(ui->checkBox_Report->isChecked()) pshow = 0;
            if(pshow) ui->label_data->clear();
            ui->label_Ready->setText("用户自定义");
            handle_request_userdef(0, _pack);
            break;
        default:
            printf("default\n"); fflush(stdout);
            break;
        }
    }
    this->adjustSize();
    qDebug() << "ViewWindow: " << result;
}

int ViewWindow::handle_request_login(const general_pack_shanghai * const _pack)
{
    const struct shanghai_login *const request = (const struct shanghai_login *const)(_pack->data);
    ViewPrint("登入时间:%04d.%02d.%02d %02d:%02d:%02d\n", request->UTC[0]+2000, request->UTC[1], request->UTC[2]\
            , request->UTC[3], request->UTC[4], request->UTC[5]);
    ViewPrint("登入流水号:%d\n", request->count);
    ViewPrint("SIM 卡号:%s\n", request->ICCID);
    return 0;
}

int ViewWindow::handle_request_logout(const general_pack_shanghai * const _pack)
{
    const struct shanghai_logout *const msg = (const struct shanghai_logout *const)(_pack->data);
    ViewPrint("登出时间:%04d.%02d.%02d %02d:%02d:%02d\n", msg->UTC[0]+2000, msg->UTC[1], msg->UTC[2]\
            , msg->UTC[3], msg->UTC[4], msg->UTC[5]);
    ViewPrint("登出流水号:%d\n", msg->count);
    return 0;
}

int ViewWindow::handle_request_userdef(int const viewer, const general_pack_shanghai * const _pack)
{
    static char text[1024];
    const struct shanghai_userdef *const msg = (const struct shanghai_userdef *const)(_pack->data);
    struct upload decode;
    int len;
    memset(&decode, 0, sizeof(struct upload));
    len = upload_decode(&decode, msg->data, msg->_dsize);
    if(len<0)
    {
        ViewPrint("userdef decode error!\n");
    }
    else
    {
        ViewPrint("decode cmd : 0x%02X\n", decode.cmd); fflush(stdout);
        ViewPrint("decode total : %d\n", decode.pack_total); fflush(stdout);
        ViewPrint("decode index : %d\n", decode.pack_index); fflush(stdout);
        ViewPrint("decode checksum : 0x%02X\n", decode.checksum); fflush(stdout);
        ViewPrint("decode Model : %s\n", decode.Model); fflush(stdout);
        ViewPrint("decode len : %d\n", decode.data_len); fflush(stdout);
        ViewPrint("decode data : %s\n", decode.data); fflush(stdout);
        ViewPrint("decode CRC : 0x%02X\n", decode.CRC); fflush(stdout);
        switch (decode.cmd)
        {
            case UPLOAD_LOGIN:  // 登录
                ViewPrint("userdef Login\n"); fflush(stdout);
                break;
            case UPLOAD_QUERY_CFG:    // 查询
                ViewPrint("userdef Config [cfg]\n"); fflush(stdout);
                //upload_query(print, _agree_ofp, &decode, ".cfg", device, csend);
                break;
            case UPLOAD_DOWNLOAD:   // 下载
                ViewPrint("userdef DownLoad\n"); fflush(stdout);
                //upload_download(*print, _agree_ofp, &decode, device, csend);
                break;
            case UPLOAD_QUERY_FW:    // 查询
                ViewPrint("userdef Firmware [bin]\n"); fflush(stdout);
                //upload_query(print, _agree_ofp, &decode, ".bin", device, csend);
                break;
            default:
                break;
        }
    }
    return 0;
}

int ViewWindow::handle_report_real(const struct general_pack_shanghai * const _pack)
{
    const struct shanghai_report_real *const msg = (const struct shanghai_report_real *const)(_pack->data);
    uint16_t index=0;
//    uint16_t data_len=0;
    static char text[4096];
    int i=0;
    struct report_head* nmsg=NULL;  // next msg
    const struct report_head* fault=NULL;
    const struct shanghai_data_obd *obd=NULL;
    const struct shanghai_data_stream *stream=NULL;
    const struct shanghai_data_att *att=NULL;
    //QString IUPR = "IUPR: ";
    //QString qstr = "";
    char _time[32];
    const uint16_t* iupr = NULL;
    char data[7][128];

    // pack
    //ui->label_pack_VIN->setText(QString("%1").arg((char*)_pack->VIN));
//    ui->groupBox_Pack->setTitle(QString("%1").arg((char*)_pack->VIN));
    //ui->label_Version->setText("软件版本号: "+QString::number(_pack->soft_version));
    ui->lineEdit_Version->setText("软件版本号: "+QString::number(_pack->soft_version));
    ui->lineEdit_ssl->setText("数据加密方式: "+QString::number(_pack->ssl));

    // OBD
    ViewPrint("Report [%d]: Time: %04d.%02d.%02d %02d:%02d:%02d \n", msg->count, msg->UTC[0]+2000, msg->UTC[1], msg->UTC[2]\
            , msg->UTC[3], msg->UTC[4], msg->UTC[5]);
    memset(_time, 0, sizeof (_time));
    snprintf(_time, sizeof (_time)-1, "时间: %04d.%02d.%02d %02d:%02d:%02d ", msg->UTC[0]+2000, msg->UTC[1], msg->UTC[2]\
            , msg->UTC[3], msg->UTC[4], msg->UTC[5]);
    //ui->label_time->setText(QString("%1").arg(_time));
    ui->lineEdit_time->setText(QString("%1").arg(_time));
    memset(text, 0, sizeof (text));
    printf("Report [%d]: Time: %04d.%02d.%02d %02d:%02d:%02d ", msg->count, msg->UTC[0]+2000, msg->UTC[1], msg->UTC[2]\
            , msg->UTC[3], msg->UTC[4], msg->UTC[5]);
    //ui->textBrowser->append(text); //ui->textBrowser->append("\n");
    fflush(stdout);
    // 消息，可包含多条
    nmsg = msg->msg;
    //pr_debug("msg.msg : %d \n", (NULL!=msg->msg)); fflush(stdout);
    while(NULL!=nmsg)
    {
        //pr_debug("type_msg : %d \n", nmsg->type_msg); fflush(stdout);
        switch (nmsg->type_msg)
        {
            // 1） OBD 信息数据格式和定义见表 A.6 所示。
            case MSG_OBD:       // 0x01  OBD 信息
                obd = (const struct shanghai_data_obd *) container_of(nmsg, struct shanghai_data_obd, head);
                {
                    uint8_t _buffer[40];
                    memset(_buffer, 0, sizeof (_buffer));
                    ViewPrint("OBD 诊断协议: %d (“0”代表 IOS15765，“1”代表IOS27145，“2”代表 SAEJ1939，“0xFE”表示无效)\n", obd->protocol);
                    ViewPrint("MIL 状态: %d (“0”代表未点亮，“1”代表点亮。“0xFE”表示无效)\n", obd->MIL);
                    memset(_buffer, 0, sizeof (_buffer));
                    //itoa(obd->status, _buffer, 2);
                    //ViewPrint("诊断支持状态: %d %s\n", obd->status, _buffer);
                    ViewPrint("诊断支持状态: %d \n", obd->status);
                    memset(_buffer, 0, sizeof (_buffer));
                    //itoa(obd->ready, _buffer, 2);
                    //ViewPrint("诊断就绪状态: %d %s\n", obd->ready, _buffer);
                    ViewPrint("诊断就绪状态: %d \n", obd->ready);
                    memset(data, 0, sizeof (data));
                    CarInfoSearch(CarListPath, (char*)obd->VIN, data[0]);
                    ViewPrint("车辆识别码（VIN）: %s 车型：%s 车牌:%s \n", obd->VIN, data[1], data[6]);
                    ViewPrint("软件标定识别号: %s \n", obd->SVIN);
                    ViewPrint("标定验证码（CVN）: %s \n", obd->CVN);
                    memset(_buffer, 0, sizeof (_buffer));
                    memcpy(_buffer, obd->IUPR, 36);
                    ViewPrint("MSG_OBD IUPR: %s \n", (char*)(_buffer));
                    ViewPrint("IUPR: ");
                    for(i=0; i<18; i++)
                    {
                        ViewPrint(" %04X",obd->IUPR[i]);
                    }
                    ViewPrint("\n");
                    ViewPrint("故障码总数: %d \n", obd->fault_total);
                }
                fault = &(obd->fault_list);
                ViewPrint("故障码: ");  // 故障码, BYTE（4）
                //while(NULL!=fault)
                for(index=0; index<obd->fault_total; index++)
                {
                    ViewPrint(" 0x%02X", fault->data);  // 故障码, BYTE（4）
                    fault = fault->next;  // 下一个数据
                    if(NULL==fault) break;
                }
                {ViewPrint("\n");fflush(stdout);}
                break;
            // 2）数据流信息数据格式和定义见表 A.7 所示，补充数据流信息数据格式和定义见表 A.8 所示。
            case MSG_STREAM:     // 0x02  数据流信息
                stream = (const struct shanghai_data_stream *)container_of(nmsg, struct shanghai_data_stream, head);
                {
                    ViewPrint("车速: %4d [%5.4f] (0~250.996km/h)\n", stream->speed, FloatConvert(stream->speed, 0, 1.0f/256));
                    ViewPrint("大气压力: %4d [%5.4f] (0~125kPa)\n", stream->kPa, FloatConvert(stream->kPa, 0, 0.5f));
                    ViewPrint("发动机净输出扭矩: %4d [%4d] (-125~125 %% “0xFF”表示无效)\n", stream->Nm, IntConvert(stream->Nm, -125, 1));
                    ViewPrint("摩擦扭矩: %4d [%4d] (-125~125%%)\n", stream->Nmf, IntConvert(stream->Nmf, -125, 1));
                    ViewPrint("发动机转速: %4d [%5.4f] (0~8031.875rpm)\n", stream->rpm, FloatConvert(stream->rpm, 0, 0.125f));
                    ViewPrint("发动机燃料流量: %4d [%5.4f] (0~3212.75L/h)\n", stream->Lh, FloatConvert(stream->Lh, 0, 0.05f));
                    ViewPrint("SCR 上游 NOx 传感器输出值: %4d [%5.4f] (-200~3212.75ppm)\n", stream->ppm_up, FloatConvert(stream->ppm_up, -200, 0.05f));
                    ViewPrint("SCR 下游 NOx 传感器输出值: %4d [%5.4f] (-200~3212.75ppm)\n", stream->ppm_down, FloatConvert(stream->ppm_down, -200, 0.05f));
                    ViewPrint("反应剂余量: %4d [%5.4f] (0~100%%)\n", stream->urea_level, FloatConvert(stream->urea_level, 0, 0.4f));
                    ViewPrint("进气量 : %4d [%5.4f] (0~3212.75ppm)\n", stream->kgh, FloatConvert(stream->kgh, 0, 0.05f));
                    ViewPrint("SCR 入口温度（后处理上游排气温度）: %4d [%5.4f] (-273~1734.96875℃)\n", stream->SCR_in, FloatConvert(stream->SCR_in, -273, 0.03125f));
                    ViewPrint("SCR 出口温度（后处理下游排气温度）: %4d [%5.4f] (-273~1734.96875℃)\n", stream->SCR_out, FloatConvert(stream->SCR_out, -273, 0.03125f));
                    ViewPrint("DPF 压差（或 DPF排气背压）: %4d [%5.4f] (0~6425.5 kPa)\n", stream->DPF, FloatConvert(stream->DPF, 0, 0.1f));
                    ViewPrint("发动机冷却液温度: %4d [%5.4f] (-40~210℃)\n", stream->coolant_temp, FloatConvert(stream->coolant_temp, -40, 1.0f));
                    ViewPrint("油箱液位: %4d [%5.4f] (0~100%%)\n", stream->tank_level, FloatConvert(stream->tank_level, 0, 0.4f));
                    ViewPrint("定位状态: %3d \n", stream->gps_status);
                    ViewPrint("经度: %4d [%5.4f] (0~180.000000°)\n", stream->longitude, DIntConvert(stream->longitude, 0, 0.000001f));
                    ViewPrint("纬度: %4d [%5.4f] (0~180.000000°)\n", stream->latitude, DIntConvert(stream->latitude, 0, 0.000001f));
                    ViewPrint("累计里程: %4d [%5.4f] (精度：0.1km)\n", stream->mileages_total, DIntConvert(stream->mileages_total, 0, 0.1f));
                    fflush(stdout);
                }
                break;
            case MSG_STREAM_ATT: // 0x80  补充数据流
                att = (const struct shanghai_data_att *)container_of(nmsg, struct shanghai_data_att, head);
                {
                    ViewPrint("发动机扭矩模式 : %3d (0：超速失效 1：转速控制 2：扭矩控制 3：转速/扭矩控制 9：正常)\n", att->Nm_mode);
                    ViewPrint("油门踏板: %3d [%5.4f] (0~100%%)\n", att->accelerator, FloatConvert(att->accelerator, 0, 0.4f));
                    ViewPrint("累计油耗: %3d [%5.4f] (0~2 105 540 607.5L)\n", att->oil_consume, DIntConvert(att->oil_consume, 0, 0.5f));
                    ViewPrint("尿素箱温度: %3d [%5.4f] (-40~210℃)\n", att->urea_tank_temp, FloatConvert(att->urea_tank_temp, -40, 1.0f));
                    ViewPrint("实际尿素喷射量: %3d [%5.4f] (精度：0.01 ml/h per bit)\n", att->mlh_urea_actual, DIntConvert(att->mlh_urea_actual, 0, 0.01f));
                    ViewPrint("累计尿素消耗 : %3d [%5.4f] (精度：1 g per bit)\n", att->mlh_urea_total, DIntConvert(att->mlh_urea_total, 0, 1.0f));
                    ViewPrint("DPF 排气温度 : %3d [%5.4f] (-273~1734.96875℃)\n", att->exit_gas_temp, FloatConvert(att->exit_gas_temp, -273, 0.03125f));
                    fflush(stdout);
                }
                break;
            // 0x03-0x7F  预留
            // 0x81~0xFE  用户自定义
            default:
                break;
        }
        nmsg = nmsg->next;   // 下一个数据
    }
    fflush(stdout);
    return 0;
}
#if 0
int print(const char *__format, ...)
{
    static char text[1024*10];
    va_list ap;
    va_start(ap, __format);
    vprintf(__format, ap);

    memset(text, 0, sizeof (text));
    //snprintf(text, sizeof (text), __format, ap);
    vsprintf(text, __format, ap);
    va_end(ap);
    printf(text); fflush(stdout);
    //printf(__format, ap); fflush(stdout);
    return 0;
}
#endif
int ViewWindow::ViewPrint(const char *__format, ...)
{
    static char text[1024*10];
    static char wbuffer[1024*10];
    static int windex=0; // 写指针
    static uint32_t seek=0;
    int _size=0;
    FILE* fd=NULL;
    va_list ap;
    va_start(ap, __format);
    //vprintf(__format, ap);
    memset(text, 0, sizeof (text));
    //snprintf(text, sizeof (text), __format, ap);
    vsprintf(text, __format, ap);
    va_end(ap);
    //printf(text); fflush(stdout);
    //printf(__format, ap); fflush(stdout);
    //ui->textBrowser->append(text);
    if(pshow) ui->label_data->setText(ui->label_data->text()+QString(text));
    _size = strlen (text);
#if 1
    memcpy(&wbuffer[windex], text, _size);
    windex += _size;
    if(windex>1024)
    {
        if(0==seek)
        {
            fd = fopen(log_path, "w");
            fclose(fd);
        }
        fd = fopen(log_path, "ab");
        if(NULL!=fd)
        {
            fwrite(wbuffer, windex, 1, fd);
            fclose(fd);
            memset(wbuffer, 0, sizeof (wbuffer));
            seek = windex;
            windex = 0;
        }
    }
#endif
    return 0;
}

#include <QByteArray>

void ViewWindow::update_vin(const char* const vin)
{
#if 0
    //char item[1024];
    int count = 0;
    int _size = 0;
    QByteArray array;
    int have=0;
    //memset(item, 0, sizeof (item));
    //ui->comboBox_List_VIN->itemText(0);
    //printf("update[%d]: %s\n", ui->comboBox_List_VIN->count(), ui->comboBox_List_VIN->itemText(0).toLatin1().data()); fflush(stdout);
    have = 0;
    _size = ui->comboBox_List_VIN->count();
    for(count=0; count<_size; count++)
    {
        array = ui->comboBox_List_VIN->itemText(count).toLatin1();
        printf("update[%d]: %s\n", _size, array.data()); fflush(stdout);
        if(0==strcmp(array.data(), vin))
        {
            have=1;
            break;
        }
    }
    if(1!=have)
    {
        array = ui->comboBox_List_VIN->itemText(0).toLatin1();
        printf("update item0: %s\n", array.data()); fflush(stdout);
        if(0==strcmp(array.data(), "NULL"))
        {
            ui->comboBox_List_VIN->clear();
        }
        ui->comboBox_List_VIN->addItem(vin);
    }
#else
    update_List(ui->comboBox_List_VIN, vin, 17);
#endif
}

void ViewWindow::update_sn(const char * const sn)
{
    update_List(ui->comboBox_List_SN, sn, 12);
}

void ViewWindow::update_List(QComboBox *comboBox_List, const char * const item, const int item_size)
{
    //char item[1024];
    int count = 0;
    int _size = 0;
    QByteArray array;
    int have=0;
    //memset(item, 0, sizeof (item));
    have = 0;
    _size = comboBox_List->count();
    if(strlen(item)<item_size) return;
    for(count=0; count<_size; count++)
    {
        array = comboBox_List->itemText(count).toLatin1();
        //printf("update[%d]: %s\n", _size, array.data()); fflush(stdout);
        if(0==strcmp(array.data(), item))
        {
            have=1;
            break;
        }
    }
    if(1!=have)
    {
        array = comboBox_List->itemText(0).toLatin1();
        //printf("update item0: %s\n", array.data()); fflush(stdout);
        if(0==strcmp(array.data(), "NULL"))
        {
            comboBox_List->clear();
        }
        comboBox_List->addItem(item);
    }
}

void ViewWindow::on_pushButton_Clear_clicked()
{
    ui->comboBox_List_VIN->clear();
    ui->comboBox_List_VIN->addItem("NULL");
    ui->comboBox_List_SN->clear();
    ui->comboBox_List_SN->addItem("NULL");
    // OBD
    static struct report_gps gps;
    static OBD_DATA obd;
    static uint8_t msg_buf[4096];
    time_t timer = time(NULL);
    gps.speed = 0;
    gps.longitude = 0;
    gps.latitude = 0;
    obd.RTData.Velocity = 0;
    obd.RTData.EngineRev = 0;
    obd.RTData.Mileage = 0;
    obd.RTData.FuelConsumption = 0;
    //memcpy(obd.ECUInfo.VIN, "LGAX4C357F3006359", 17);
    time(&timer);
    shanghai_report_real * _data = shanghai_report_msg(timer, &obd, &gps, msg_buf, sizeof (msg_buf));
    general_pack_shanghai _pack;
    memset(&_pack, 0, sizeof(_pack));
    _pack.data = _data;
    ui->label_data->clear();
    pshow = 1;
    handle_report_real(&_pack);
}

void ViewWindow::on_checkBox_VIN_clicked()
{
    //ui->lineEdit_VIN->setEnabled(!ui->checkBox_VIN->isChecked());
}

void ViewWindow::on_checkBox_SN_clicked()
{
    static int count=0;
    //ui->lineEdit_SN->setEnabled(!ui->checkBox_SN->isChecked());
    ViewPrint("Box:%d\n", count++);
}
